#include "Database.h"

// INSERT SINGLE RECORD
bool InsertRecordMhs(AddressMhs Mhs, TabelMhs *TMhs, nodeAddress to, nodeAddress from, edgeList Graph, float *out_time, char *out_shortestpath) {
	GraphShortestPath(GetRecordMhsSize(Mhs), UPLOAD, Graph, from, to, out_time, out_shortestpath);
	
	if(*out_time>=MAXTIME) {
		return false;
	}
	
	if(SearchRecordMhs(Mhs,TMhs)==NULL) AddRecordMhs(Mhs, TMhs);
	if(SearchOwnerByNode(&OWNERLIST(Mhs),to)==NULL) {
		ownerAddress O = AllocateOwnerList(to);
		if(O) {
			AddOwnerToRecordMhs(Mhs, O);
		}
		return O!=NULL;
	}
	else return false;
}

bool InsertRecordMK(AddressMK MK, TabelMK *TMK, nodeAddress to, nodeAddress from, edgeList Graph, float *out_time, char *out_shortestpath) {
	GraphShortestPath(GetRecordMKSize(MK), UPLOAD, Graph, from, to, out_time, out_shortestpath);
	
	if(*out_time>=MAXTIME) return false;
	
	if(SearchRecordMK(MK,TMK)==NULL) AddRecordMK(MK, TMK);
	if(SearchOwnerByNode(&OWNERLIST(MK),to)==NULL) {
		ownerAddress O = AllocateOwnerList(to);
		if(O) {
			AddOwnerToRecordMK(MK, O);
		}
		return O!=NULL;
	}
	else return false;
}

bool InsertRecordPMK(AddressPMK PMK, TabelPMK *TPMK, nodeAddress to, nodeAddress from, edgeList Graph, float *out_time, char *out_shortestpath) {
	GraphShortestPath(GetRecordPMKSize(PMK), UPLOAD, Graph, from, to, out_time, out_shortestpath);
	
	if(*out_time>=MAXTIME) return false;
	
	if(SearchRecordPMK(PMK,TPMK)==NULL) AddRecordPMK(PMK, TPMK);
	if(SearchOwnerByNode(&OWNERLIST(PMK),to)==NULL) {
		ownerAddress O = AllocateOwnerList(to);
		if(O) {
			AddOwnerToRecordPMK(PMK, O);
			UpdateIPKdanJmlSKSRecordMhs(MHS(PMK), TPMK);
		}
		return O!=NULL;
	}
	else return false;
}



// DELETE SINGLE RECORD
void DeleteRecordMhs(AddressMhs Mhs, TabelMhs *TMhs, TabelPMK *TPMK, float *del_time, int *MhsRecordCount) {
	float deltime = 0;
	int RecMhsCount = 0;
	
	// Update TabelPMK dulu
	if(!ISLINKEDLISTEMPTY(*TPMK)) {
		AddressPMK PMK;
		AddressPMK next;
		for(PMK=FIRST(*TPMK),next=NEXT(PMK); PMK!=NULL; PMK = next,next=(PMK==NULL ? NULL : NEXT(PMK))) {
			if(MHS(PMK)==Mhs) {
				DestroyRecordPMK(PMK,TPMK);
			}
		}
	}
	
	// Update TabelMhs
	ownerAddress O = NULL;
	TRAVERSETOEND2(O,FIRST(OWNERLIST(Mhs))) {
		RecMhsCount++;
		deltime+=DELETETIME(NODE(O));
	}
	DestroyRecordMhs(Mhs, TMhs);
	
	UpdateIPKdanJmlSKSRecordMhs(Mhs, TPMK);
	
	*del_time = deltime;
	*MhsRecordCount = RecMhsCount;
}

void DeleteRecordMK(AddressMK MK, TabelMK *TMK, TabelPMK *TPMK, float *del_time, int *MKRecordCount) {
	float deltime = 0;
	int RecMKCount = 0;
	
	// Update TabelPMK dulu
	if(!ISLINKEDLISTEMPTY(*TPMK)) {
		AddressPMK PMK;
		AddressPMK next;
		for(PMK=FIRST(*TPMK),next=NEXT(PMK); PMK!=NULL; PMK = next,next=(PMK==NULL ? NULL : NEXT(PMK))) {
			if(MK(PMK)==MK) {
				AddressMhs Mhs = MHS(PMK);
				DestroyRecordPMK(PMK,TPMK);
				UpdateIPKdanJmlSKSRecordMhs(Mhs, TPMK);
			}
		}
	}
	
	// Update TabelMhs
	ownerAddress O = NULL;
	TRAVERSETOEND2(O,FIRST(OWNERLIST(MK))) {
		RecMKCount++;
		deltime+=DELETETIME(NODE(O));
	}
	DestroyRecordMK(MK, TMK);
	
	*del_time = deltime;
	*MKRecordCount = RecMKCount;
}

void DeleteRecordPMK(AddressPMK PMK, TabelPMK *TPMK, float *del_time, int *PMKRecordCount) {
	float deltime = 0;
	int RecPMKCount = 0;
	
	
	// Update TabelPMK
	ownerAddress O = NULL;
	TRAVERSETOEND2(O,FIRST(OWNERLIST(PMK))) {
		RecPMKCount++;
		deltime+=DELETETIME(NODE(O));
	}
	
	AddressMhs Mhs = MHS(PMK);
	
	// dealokasi recordPMK
	DestroyRecordPMK(PMK, TPMK);
	
	// update Mhs
	UpdateIPKdanJmlSKSRecordMhs(Mhs, TPMK);
	
	*del_time = deltime;
	*PMKRecordCount = RecPMKCount;
}

// UPDATE SINGLE RECORD
void UpdateRecordMhs(AddressMhs Mhs, string NIMbaru, string namaBaru, date TglLahirBaru, string KotaAsalBaru, int *out_count, float *out_time) {
	*out_count = 0;
	*out_time = 0;
	
	ChangeRecordMhsContent(Mhs, NIMbaru, namaBaru, TglLahirBaru, KotaAsalBaru);
	ownerAddress O = NULL;
	TRAVERSETOEND2(O,FIRST(OWNERLIST(Mhs))) {
		(*out_count)++;
		(*out_time)+=UPDATETIME(NODE(O));
	}
}

void UpdateRecordMK(AddressMK MK, string kodeBaru, string namaBaru, int SKSBaru, string bidangBaru, int *out_count, float *out_time) {
	*out_count = 0;
	*out_time = 0;
	
	ChangeRecordMKContent(MK, kodeBaru, namaBaru, SKSBaru, bidangBaru);
	ownerAddress O = NULL;
	TRAVERSETOEND(O,FIRST(OWNERLIST(MK))) {
		(*out_count)++;
		(*out_time)+=UPDATETIME(NODE(O));
	}
	if(O) {
		(*out_count)++;
		(*out_time)+=UPDATETIME(NODE(O));
	}
}

void UpdateRecordPMK(AddressPMK PMK, AddressMhs MhsBaru, AddressMK MKBaru, int semesterBaru, ThnAkademik TABaru, char nilaiBaru, int *out_count, float *out_time) {
	*out_count = 0;
	*out_time = 0;
	
	ChangeRecordPMKContent(PMK, MhsBaru, MKBaru, semesterBaru, TABaru, nilaiBaru);
	ownerAddress O = NULL;
	TRAVERSETOEND(O,FIRST(OWNERLIST(PMK))) {
		(*out_count)++;
		(*out_time)+=UPDATETIME(NODE(O));
	}
	if(O) {
		(*out_count)++;
		(*out_time)+=UPDATETIME(NODE(O));
	}
}


// RETRIEVE SINGLE RECORD
void RetrieveRecordMhs(AddressMhs Mhs, nodeAddress from, edgeList Graph, char *out_shortestpath, float *out_retrievetime) {
	float retrievetime;
	char shortestpath[100];
	
	ownerAddress O = FIRST(OWNERLIST(Mhs));
	if(O) {
		GraphShortestPath(GetRecordMhsSize(Mhs), DOWNLOAD, Graph, from, NODE(O), out_retrievetime, out_shortestpath);
	}
	
	TRAVERSETOEND2(O,NEXT(FIRST(OWNERLIST(Mhs)))) {
		GraphShortestPath(GetRecordMhsSize(Mhs), DOWNLOAD, Graph, from, NODE(O), &retrievetime, shortestpath);
		if(retrievetime < *out_retrievetime) {
			*out_retrievetime = retrievetime;
			CopyStr(out_shortestpath,shortestpath);
		}
	}
}

void RetrieveRecordMK(AddressMK MK, nodeAddress from, edgeList Graph, char *out_shortestpath, float *out_retrievetime) {
	float retrievetime;
	char shortestpath[100];
	
	ownerAddress O = FIRST(OWNERLIST(MK));
	if(O) {
		GraphShortestPath(GetRecordMKSize(MK), DOWNLOAD, Graph, from, NODE(O), out_retrievetime, out_shortestpath);
	}
	
	TRAVERSETOEND2(O,NEXT(FIRST(OWNERLIST(MK)))) {
		GraphShortestPath(GetRecordMKSize(MK), DOWNLOAD, Graph, from, NODE(O), &retrievetime, shortestpath);
		if(retrievetime < *out_retrievetime) {
			*out_retrievetime = retrievetime;
			CopyStr(out_shortestpath,shortestpath);
		}
	}
}

void RetrieveRecordPMK(AddressPMK PMK, nodeAddress from, edgeList Graph, char *out_shortestpath, float *out_retrievetime) {
	float retrievetime;
	char shortestpath[100];
	
	ownerAddress O = FIRST(OWNERLIST(PMK));
	if(O) {
		GraphShortestPath(GetRecordPMKSize(PMK), DOWNLOAD, Graph, from, NODE(O), out_retrievetime, out_shortestpath);
	}
	
	TRAVERSETOEND2(O,NEXT(FIRST(OWNERLIST(PMK)))) {
		GraphShortestPath(GetRecordPMKSize(PMK), DOWNLOAD, Graph, from, NODE(O), &retrievetime, shortestpath);
		if(retrievetime < *out_retrievetime) {
			*out_retrievetime = retrievetime;
			CopyStr(out_shortestpath,shortestpath);
		}
	}
}
